package com.fowo.api.syncAmazon.core.dataRecovery;

import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fowo.api.entity.*;
import com.fowo.api.service.impl.ListingFatherServiceImpl;
import com.fowo.api.service.impl.SellOrderServiceImpl;
import com.fowo.api.syncAmazon.entity.AmazonBusinessReportsByChild;
import com.fowo.api.syncAmazon.entity.AmazonSpAdvertisedProductReport;
import com.fowo.api.syncAmazon.mapper.syncDataRecoveryMapper;
import com.fowo.api.sys.service.impl.SysMailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.mail.MessagingException;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.function.Function;


/**
 * @description: 不完整的同步数据修复
 * @author: xqw
 * @time: 2024/4/29 14:28
 */
@Component
public class syncDataRecovery {

    @Autowired
    private syncDataRecoveryMapper syncDataRecoveryMapper;

    @Autowired
    private SellOrderServiceImpl sellOrderService;

    @Autowired
    private ListingFatherServiceImpl listingFatherService;

    @Autowired
    protected SysMailServiceImpl sysMailService;

    @Value("${spring.mail.addressee}")
    private String addressee;

    /**
     * 数据修复人口
     * 修复sid为null或innerLID为null和日期（create_time）30天之内的数据
     */
    public void entrance() {
        // 查询出 sid 或 innerLID 字段值为 null 的数据(日期在30天内)
        Map<String, List<?>> recoveryData = prepare();

        // 修复 sid 和 innerLID字段
        recovery(recoveryData);

        // 更新修复后的 sid 和 innerLID
        Map<String, List<Integer>> recoveryDetail = update(recoveryData);

        // 构造汇总邮件内容
        Map<String, Object> variables = createTemplateData(recoveryDetail);

        // 发送汇总邮件
        try {
            sysMailService.send(addressee, "'亚马逊拉取数据的修复报告--" + LocalDate.now() + "'", "data-recovery-report.html", variables);
        } catch (MessagingException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 查询出 sid 或 innerLID 字段值为 null 的数据(日期在30天内)
     */
    private Map<String, List<?>> prepare() {
        Map<String, List<?>> recoveryData = new HashMap<>();

        // 亚马逊销售统计表 sid 或 innerLID 字段值为 null 的数据
        List<AmazonSalesStatement> amazonSalesStatementList = syncDataRecoveryMapper.selectSalesStatementSidOrInnerLIDIsNull();
        recoveryData.put("amazon_sales_statement", amazonSalesStatementList);

        //FBA库存表 listing_id 为 null 的数据
        List<FBAInventory> fbaInventoryList = syncDataRecoveryMapper.selectFBAInventoryListingIdIsNull();
        recoveryData.put("fba_inventory", fbaInventoryList);

        // 子商品业务报表 innerLID 字段值为 null 的数据
        List<AmazonBusinessReportsByChild> businessReportsByChildList = syncDataRecoveryMapper.selectBusinessReportsByChildInnerLIDIsNull();
        recoveryData.put("amazon_business_reports_by_child", businessReportsByChildList);

        // sp广告产品报表 innerLID 字段值为 null 的数据
        List<AmazonSpAdvertisedProductReport> spAdvertisedProductList = syncDataRecoveryMapper.selectSpAdvertisedProductInnerLIDIsNull();
        recoveryData.put("amazon_sp_advertised_product_report", spAdvertisedProductList);

        return recoveryData;
    }

    /**
     * 修复 sid 和 innerLID 为 null 的数据
     */
    private void recovery(Map<String, List<?>> recoveryData) {
        // 修复 亚马逊销售统计表 sid 和 innerLID 为 null 的数据
        List<AmazonSalesStatement> amazonSalesStatementList = (List<AmazonSalesStatement>) recoveryData.get("amazon_sales_statement");
        if (amazonSalesStatementList != null && amazonSalesStatementList.size() > 0) {
            recoveryAmazonSalesStatement(amazonSalesStatementList);
        }

        // 修复 FBA库存表 listing_id 为 null 的数据
        List<FBAInventory> fbaInventoryList = (List<FBAInventory>) recoveryData.get("fba_inventory");
        if (fbaInventoryList != null && fbaInventoryList.size() > 0) {
            recoveryFBAInventory(fbaInventoryList);
        }

        // 修复 子商品业务报表 innerLID 字段值为 null 的数据
        List<AmazonBusinessReportsByChild> businessReportsByChildList = (List<AmazonBusinessReportsByChild>) recoveryData.get("amazon_business_reports_by_child");
        if (businessReportsByChildList != null && businessReportsByChildList.size() > 0) {
            recoveryBusinessReportsByChild(businessReportsByChildList);
        }

        // 修复 sp产品广告报表 innerLID 字段值为 null 的数据
        List<AmazonSpAdvertisedProductReport> spAdvertisedProductList = (List<AmazonSpAdvertisedProductReport>) recoveryData.get("amazon_sp_advertised_product_report");
        if (spAdvertisedProductList != null && spAdvertisedProductList.size() > 0) {
            recoverySpAdvertisedProduct(spAdvertisedProductList);
        }
    }

    // 修复 sp产品广告报表 innerLID 字段值为 null 的数据
    private void recoverySpAdvertisedProduct(List<AmazonSpAdvertisedProductReport> spAdvertisedProductList) {
        List<ListingFather> listingFatherList = new ArrayList<>();
        // 分批查询
        for (List<AmazonSpAdvertisedProductReport> spAdvertisedProductBatchList : ListUtil.partition(spAdvertisedProductList, 500)) {
            // 修复 innerLID: advertised_asin + sid 查找 listing_father表的 id
            List<String> advertisedAsinList = spAdvertisedProductBatchList.stream().map(AmazonSpAdvertisedProductReport::getAdvertisedAsin).collect(Collectors.toList());
            // 数据库查询 advertised_asin 符合的数据
            List<ListingFather> listingFathersTmp = listingFatherService.list(new QueryWrapper<ListingFather>().in("asin", advertisedAsinList));
            // 筛选 advertised_asin + sid 符合的 listingFather
            for (AmazonSpAdvertisedProductReport spAdvertisedProduct : spAdvertisedProductBatchList) {
                List<ListingFather> tmp = listingFathersTmp.stream().filter(l -> l.getAsin().equals(spAdvertisedProduct.getAdvertisedAsin()) && l.getShop().equals(spAdvertisedProduct.getSid())).collect(Collectors.toList());
                listingFatherList.addAll(tmp);
            }
        }

        // 对 innerLID 进行修复: listing_father 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
        for (AmazonSpAdvertisedProductReport spAdvertisedProduct : spAdvertisedProductList) {
            // 找到与之映射的 listingFather
            List<ListingFather> collect = listingFatherList.stream()
                    .filter(l -> l.getAsin().equals(spAdvertisedProduct.getAdvertisedAsin()) && l.getShop().equals(spAdvertisedProduct.getSid())).collect(Collectors.toList());

            // 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
            if (collect != null && collect.size() > 0) {
                Optional<ListingFather> exist1 = collect.stream().filter(r -> r.getStatus().equals("1")).findFirst();
                Optional<ListingFather> exist0 = collect.stream().filter(r -> r.getStatus().equals("0")).findFirst();
                Optional<ListingFather> exist2 = collect.stream().filter(r -> r.getStatus().equals("2")).findFirst();
                if (exist1.isPresent()) {
                    spAdvertisedProduct.setInnerlid(exist1.get().getId());
                } else if (exist0.isPresent()) {
                    spAdvertisedProduct.setInnerlid(exist0.get().getId());
                } else if (exist2.isPresent()) {
                    spAdvertisedProduct.setInnerlid(exist2.get().getId());
                }
            }
        }
    }

    // 修复 亚马逊销售统计表 sid 和 innerLID 为 null 的数据
    private void recoveryAmazonSalesStatement(List<AmazonSalesStatement> amazonSalesStatementList) {
        List<ListingFather> listingFatherList = new ArrayList<>();
        // 分批查询
        for (List<AmazonSalesStatement> amazonBatchList : ListUtil.partition(amazonSalesStatementList, 500)) {
            // 修复 sid: 通过 amazon_order_id 查找 sell_order表的 sid
            List<String> amazonOrderIdList = amazonBatchList.stream().map(AmazonSalesStatement::getAmazonOrderId).collect(Collectors.toList());
            List<SellOrder> sellOrderList = sellOrderService.list(new QueryWrapper<SellOrder>().in("amazon_order_id", amazonOrderIdList));
            // amazon_order_id 映射的 AmazonSalesStatement 和 SellOrder， 将 SellOrder 的 sid 给 AmazonSalesStatement
            for (AmazonSalesStatement amazonSalesStatement : amazonBatchList) {
                List<Long> sids = sellOrderList.stream().filter(s -> s.getAmazonOrderId().equals(amazonSalesStatement.getAmazonOrderId())).map(SellOrder::getSid).collect(Collectors.toList());
                if (sids != null && sids.size() > 0) {
                    amazonSalesStatement.setSid(sids.get(0));
                }
            }

            // 修复 innerLID: msku + sid 查找 listing_father表的 id
            List<String> mskuList = amazonBatchList.stream().map(AmazonSalesStatement::getMsku).collect(Collectors.toList());
            // 数据库查询 msku 符合的数据
            List<ListingFather> listingFathersTmp = listingFatherService.list(new QueryWrapper<ListingFather>().in("msku", mskuList));
            // 筛选 msku + sid 符合的 listingFather
            for (AmazonSalesStatement amazonSalesStatement : amazonBatchList) {
                List<ListingFather> tmp = listingFathersTmp.stream().filter(l -> l.getMsku().equals(amazonSalesStatement.getMsku()) && l.getShop().equals(amazonSalesStatement.getSid())).collect(Collectors.toList());
                listingFatherList.addAll(tmp);
            }
        }

        // 对 innerLID 进行修复: listing_father 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
        for (AmazonSalesStatement amazonSalesStatement : amazonSalesStatementList) {
            // 找到与之映射的 listingFather
            List<ListingFather> collect = listingFatherList.stream()
                    .filter(l -> l.getMsku().equals(amazonSalesStatement.getMsku()) && l.getShop().equals(amazonSalesStatement.getSid())).collect(Collectors.toList());

            // 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
            if (collect != null && collect.size() > 0) {
                Optional<ListingFather> exist1 = collect.stream().filter(r -> r.getStatus().equals("1")).findFirst();
                Optional<ListingFather> exist0 = collect.stream().filter(r -> r.getStatus().equals("0")).findFirst();
                Optional<ListingFather> exist2 = collect.stream().filter(r -> r.getStatus().equals("2")).findFirst();
                if (exist1.isPresent()) {
                    amazonSalesStatement.setInnerLID(exist1.get().getId());
                } else if (exist0.isPresent()) {
                    amazonSalesStatement.setInnerLID(exist0.get().getId());
                } else if (exist2.isPresent()) {
                    amazonSalesStatement.setInnerLID(exist2.get().getId());
                }
            }
        }
    }

    // 修复 FBA库存表 listing_id 为 null 的数据
    private void recoveryFBAInventory(List<FBAInventory> fbaInventoryList) {
        List<ListingFather> listingFatherList = new ArrayList<>();
        // 分批查询
        for (List<FBAInventory> fbaInventoryBatchList : ListUtil.partition(fbaInventoryList, 500)) {
            // 修复 innerLID: msku + sid 查找 listing_father表的 id
            List<String> mskuList = fbaInventoryBatchList.stream().map(FBAInventory::getMsku).collect(Collectors.toList());
            // 数据库查询 msku 符合的数据
            List<ListingFather> listingFathersTmp = listingFatherService.list(new QueryWrapper<ListingFather>().in("msku", mskuList));
            // 筛选 msku + sid 符合的 listingFather
            for (FBAInventory fBAInventory : fbaInventoryBatchList) {
                List<ListingFather> tmp = listingFathersTmp.stream().filter(l -> l.getMsku().equals(fBAInventory.getMsku()) && l.getShop().equals(fBAInventory.getSid())).collect(Collectors.toList());
                listingFatherList.addAll(tmp);
            }
        }

        // 对 innerLID 进行修复: listing_father 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
        for (FBAInventory fBAInventory : fbaInventoryList) {
            // 找到与之映射的 listingFather
            List<ListingFather> collect = listingFatherList.stream()
                    .filter(l -> l.getMsku().equals(fBAInventory.getMsku()) && l.getShop().equals(fBAInventory.getSid())).collect(Collectors.toList());

            // 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
            if (collect != null && collect.size() > 0) {
                Optional<ListingFather> exist1 = collect.stream().filter(r -> r.getStatus().equals("1")).findFirst();
                Optional<ListingFather> exist0 = collect.stream().filter(r -> r.getStatus().equals("0")).findFirst();
                Optional<ListingFather> exist2 = collect.stream().filter(r -> r.getStatus().equals("2")).findFirst();
                if (exist1.isPresent()) {
                    fBAInventory.setListingId(exist1.get().getId());
                } else if (exist0.isPresent()) {
                    fBAInventory.setListingId(exist0.get().getId());
                } else if (exist2.isPresent()) {
                    fBAInventory.setListingId(exist2.get().getId());
                }
            }
        }
    }

    // 修复 子商品业务报表 innerLID 字段值为 null 的数据
    private void recoveryBusinessReportsByChild(List<AmazonBusinessReportsByChild> businessReportsByChildList) {
        List<ListingFather> listingFatherList = new ArrayList<>();
        // 分批查询
        for (List<AmazonBusinessReportsByChild> businessReportsByChildBatchList : ListUtil.partition(businessReportsByChildList, 500)) {
            // 修复 innerLID: child_asin + sid 查找 listing_father表的 id
            List<String> childAsinList = businessReportsByChildBatchList.stream().map(AmazonBusinessReportsByChild::getChildAsin).collect(Collectors.toList());
            // 数据库查询 asin 符合的数据
            List<ListingFather> listingFathersTmp = listingFatherService.list(new QueryWrapper<ListingFather>().in("asin", childAsinList));
            // 筛选 asin + sid 符合的 listingFather
            for (AmazonBusinessReportsByChild businessReportsByChild : businessReportsByChildBatchList) {
                List<ListingFather> tmp = listingFathersTmp.stream().filter(l -> l.getAsin().equals(businessReportsByChild.getChildAsin()) && l.getShop().equals(businessReportsByChild.getSid())).collect(Collectors.toList());
                listingFatherList.addAll(tmp);
            }
        }

        // 对 innerLID 进行修复: listing_father 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
        for (AmazonBusinessReportsByChild businessReportsByChild : businessReportsByChildList) {
            // 找到与之映射的 listingFather
            List<ListingFather> collect = listingFatherList.stream()
                    .filter(l -> l.getAsin().equals(businessReportsByChild.getChildAsin()) && l.getShop().equals(businessReportsByChild.getSid())).collect(Collectors.toList());

            // 优先取status为1（在售）的数据的id,其次status为0（停售）最后为2（已删除），如果没有就不取
            if (collect != null && collect.size() > 0) {
                Optional<ListingFather> exist1 = collect.stream().filter(r -> r.getStatus().equals("1")).findFirst();
                Optional<ListingFather> exist0 = collect.stream().filter(r -> r.getStatus().equals("0")).findFirst();
                Optional<ListingFather> exist2 = collect.stream().filter(r -> r.getStatus().equals("2")).findFirst();
                if (exist1.isPresent()) {
                    businessReportsByChild.setInnerLID(exist1.get().getId());
                } else if (exist0.isPresent()) {
                    businessReportsByChild.setInnerLID(exist0.get().getId());
                } else if (exist2.isPresent()) {
                    businessReportsByChild.setInnerLID(exist2.get().getId());
                }
            }
        }
    }



    /**
     * 更新修复后的 sid 和 innerLID
     * @param recoveryData 往数据库更新的数据
     * @return 更新的数据量
     */
    private Map<String, List<Integer>> update(Map<String, List<?>> recoveryData) {
        Map<String, List<Integer>> result = new HashMap<>();

        // 修复 亚马逊销售统计表 sid 和 innerLID 为 null 的数据
        updateEntities(recoveryData, "amazon_sales_statement", AmazonSalesStatement.class, "innerLID", syncDataRecoveryMapper::updateSalesStatementSidAndInnerLID, result);
        // 修复 FBA库存表 listing_id 为 null 的数据
        updateEntities(recoveryData, "fba_inventory", FBAInventory.class, "listingId", syncDataRecoveryMapper::updateFBAInventoryListingId, result);
        // 修复 子商品业务报表 innerLID 为 null 的数据
        updateEntities(recoveryData, "amazon_business_reports_by_child", AmazonBusinessReportsByChild.class, "innerLID", syncDataRecoveryMapper::updateBusinessReportsByChildInnerLID, result);
        // 修复 sp产品广告报表 innerLID 为 null 的数据
        updateEntities(recoveryData, "amazon_sp_advertised_product_report", AmazonSpAdvertisedProductReport.class, "innerlid", syncDataRecoveryMapper::updateSpAdvertisedProductInnerLID, result);

        return result;
    }

    /**
     * 调用不同的 update方法，将修复的数据更新到数据库
     * @param recoveryData 修复的数据
     * @param key 修复的表名
     * @param entityType 对应实体的类型
     * @param recoveryField 修复字段的名称
     * @param updateFunction 更新方法
     * @param result 修复详情：修复数据量  未修复数据量
     * @param <T> 实体的类型
     */
    private <T> void updateEntities(Map<String, List<?>> recoveryData, String key, Class<T> entityType, String recoveryField, Function<T, Integer> updateFunction, Map<String, List<Integer>> result) {
        List<T> entityList = (List<T>) recoveryData.get(key);
        if (entityList != null && !entityList.isEmpty()) {
            // 修复数据量
            int updatedCount = 0;
            int totalCount = entityList.size();

            // 去除 innerLID 仍然都为空的
            List<T> filteredList = entityList.stream()
                    .filter(entity -> entity != null && getPrivateField(entity, recoveryField) != null)
                    .collect(Collectors.toList());

            // 更新修复后的 innerLID 或 sid
            for (T entity : filteredList) {
                updatedCount += updateFunction.apply(entity);
            }

            // 修复详情：修复数据量  未修复数据量
            List<Integer> detail = List.of(updatedCount, totalCount - updatedCount);
            result.put(key, detail);
        }
    }

    // 通过反射访问 T类型的 fieldName 属性
    private static <T> Object getPrivateField(T entity, String fieldName) {
        try {
            Field field = entity.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(entity);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException("反射访问字段失败: " + fieldName, e);
        }
    }

    /**
     * 创建修复模板数据
     * @param recoveryDetail
     * @return
     */
    public Map<String, Object> createTemplateData(Map<String, List<Integer>> recoveryDetail) {
        Map<String, Object> variables = new HashMap<>();
        List<Map<String, Object>> dataList = new ArrayList<>();

        for (String s : recoveryDetail.keySet()) {
            List<Integer> detail = recoveryDetail.get(s);
            if ("amazon_sales_statement".equals(s) && detail != null && detail.size() == 2) {
                //  修复对象:销售统计表(amazon_sales_statement)  修复内容: 30天内的无值sid和innerLID字段数据   修复数据量:   修复时间:
                dataList.add(getTemplateItemData("销售统计表(amazon_sales_statement)", "30天内sid和innerLID字段无值的数据", detail));
            }
            if ("fba_inventory".equals(s) && detail != null && detail.size() == 2) {
                //  修复对象:FBA库存表(fba_inventory)  修复内容: 30天内的无值listing_id字段数据   修复数据量:   修复时间:
                dataList.add(getTemplateItemData("FBA库存表(fba_inventory)", "listing_id字段无值的数据", detail));
            }

            if ("amazon_business_reports_by_child".equals(s) && detail != null && detail.size() == 2) {
                //  修复对象:子商品业务报表(amazon_business_reports_by_child)  修复内容: 30天内的无值innerLID字段数据   修复数据量:   修复时间:
                dataList.add(getTemplateItemData("子商品业务报表(amazon_business_reports_by_child)", "30天内innerLID字段无值的数据", detail));
            }

            if ("amazon_sp_advertised_product_report".equals(s) && detail != null && detail.size() == 2) {
                //  修复对象:子商品业务报表(amazon_business_reports_by_child)  修复内容: 30天内的无值innerLID字段数据   修复数据量:   修复时间:
                dataList.add(getTemplateItemData("sp产品广告报表(amazon_sp_advertised_product_report)", "30天内innerLID字段无值的数据", detail));
            }
        }

        variables.put("dataList", dataList);

        return variables;
    }

    // 构造单行修复信息
    private Map<String, Object> getTemplateItemData(String recoveryObject, String message, List<Integer> detailData) {
        Map<String, Object> record = new HashMap<>();
        record.put("recoveryObject", recoveryObject);
        record.put("message", message);
        record.put("dataVolume", detailData.get(0));
        record.put("noRecoveryVolume", detailData.get(1));
        record.put("recoveryTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSS")));
        return record;
    }

}
